package com.quick.develop.form.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.quick.develop.form.entity.GenDynamicFormFieldEntity;
import com.quick.develop.form.service.GenDynamicFormFieldService;
import com.quick.develop.form.utils.ExcelUtils;
import com.quick.develop.framework.common.annotation.CreateForm;
import com.quick.develop.framework.common.annotation.DetailForm;
import com.quick.develop.framework.common.annotation.UpdateForm;
import com.quick.develop.framework.common.exception.ServerException;
import com.quick.develop.framework.common.page.PageResult;
import com.quick.develop.framework.common.service.impl.BaseServiceImpl;
import com.quick.develop.form.convert.GenDynamicFormConvert;
import com.quick.develop.form.dao.GenDynamicFormDao;
import com.quick.develop.form.entity.GenDynamicFormEntity;
import com.quick.develop.form.entity.GenDynamicFormGroupEntity;
import com.quick.develop.form.query.GenDynamicFormQuery;
import com.quick.develop.form.vo.FormConfigVO;
import com.quick.develop.form.vo.FormGroupVO;
import com.quick.develop.form.vo.GenDynamicFormVO;
import com.quick.develop.form.convert.GenDynamicFormGroupConvert;
import com.quick.develop.form.service.GenDynamicFormGroupService;
import com.quick.develop.form.service.GenDynamicFormService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;

/**
 * 动态表单
 *
 * @author 阿沐 babamu@126.com
 * @since 1.0.0 2023-09-24
 */
@Service(value = "dynamicForm")
@AllArgsConstructor
public class GenDynamicFormServiceImpl extends BaseServiceImpl<GenDynamicFormDao, GenDynamicFormEntity> implements GenDynamicFormService {

    @Resource
    public GenDynamicFormGroupService dynamicFormGroupService;

    @Resource
    public GenDynamicFormFieldService dynamicFormFieldService;

    @Override
    public PageResult<GenDynamicFormVO> page(GenDynamicFormQuery query) {
        IPage<GenDynamicFormEntity> page = baseMapper.selectPage(getPage(query), getWrapper(query));

        return new PageResult<>(GenDynamicFormConvert.INSTANCE.convertList(page.getRecords()), page.getTotal());
    }

    private LambdaQueryWrapper<GenDynamicFormEntity> getWrapper(GenDynamicFormQuery query) {
        LambdaQueryWrapper<GenDynamicFormEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(!StrUtil.isBlankIfStr(query.getBusinessType()), GenDynamicFormEntity::getBusinessType, query.getBusinessType());
        wrapper.and(!StrUtil.isBlankIfStr(query.getKeyword()),
                like -> like.like(GenDynamicFormEntity::getName, query.getKeyword()).or()
                        .like(GenDynamicFormEntity::getCode, query.getKeyword()));
        return wrapper;
    }

    @CreateForm
    @Override
    public void save(GenDynamicFormVO vo) {
        GenDynamicFormEntity entity = GenDynamicFormConvert.INSTANCE.convert(vo);

        baseMapper.insert(entity);
    }

    @UpdateForm
    @Override
    public void update(GenDynamicFormVO vo) {
        GenDynamicFormEntity entity = GenDynamicFormConvert.INSTANCE.convert(vo);

        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> idList) {
        removeByIds(idList);
    }

    @Override
    @DetailForm
    public Object getDynamicFormDetail(String id) {
        return getOne(Wrappers.lambdaUpdate(GenDynamicFormEntity.class)
                .eq(GenDynamicFormEntity::getBusinessKey, id));
    }

    @Override
    public FormConfigVO getDynamicForm(FormConfigVO formConfigVO) {

        if (Objects.isNull(formConfigVO.getId())) {

            FormConfigVO formEntity = new FormConfigVO();
            formEntity.setCode("Activity_" + generateActivityCode());
            formEntity.setName("活动表单_" + generateActivityCode());
            formEntity.setGroups(new ArrayList<>());
            formEntity.setSize("small");
            save(formEntity);

            GenDynamicFormGroupEntity group = new GenDynamicFormGroupEntity();
            group.setFormId(formEntity.getId());
            group.setName("默认表单");
            group.setKey(formConfigVO.getCode());
            dynamicFormGroupService.save(group);

            FormGroupVO formGroupVO = GenDynamicFormGroupConvert.INSTANCE.convertFormVo(group);
            formGroupVO.setElements(Collections.emptyList());
            formEntity.setGroups(Collections.singletonList(formGroupVO));
            return formEntity;
        }

        return getFormConfigById(formConfigVO.getId());
    }

    @Override
    public FormConfigVO getFormConfigByFormKey(String key) {

        LambdaQueryWrapper<GenDynamicFormEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(GenDynamicFormEntity::getCode, key);

        GenDynamicFormEntity formEntity = getOne(wrapper);

        if (Objects.isNull(formEntity)) {
            return getDynamicForm(new FormConfigVO());
        }

        return getFormConfigById(formEntity.getId());
    }

    @Override
    public void dynamicExportExcel(GenDynamicFormQuery query) {
        List<GenDynamicFormEntity> list = this.list(getWrapper(query));
        ExcelUtils.downloadExcel(GenDynamicFormEntity.class, list, "动态表单导出");
    }

    @Override
    public void dynamicImportExcel(MultipartFile file) {
        ExcelUtils.execWriteDatabase(
                file,
                GenDynamicFormEntity.class,
                this::filterDynamicImport,
                this::overrideDynamicImport,
                this::updateBatchById,
                this::saveBatch
        );
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void formCV(Integer formId) {
        FormConfigVO formConfig = getFormConfigById(formId);
        if (Objects.isNull(formConfig)) {
            throw new ServerException("表单不存在");
        }
        GenDynamicFormEntity formEntity = GenDynamicFormConvert.INSTANCE.convert(formConfig);
        formEntity.setCode(formEntity.getCode() + "(1)");
        formEntity.setName(formEntity.getName() + "(1)");
        formEntity.setId(null);
        save(formEntity);
        List<FormGroupVO> groups = formConfig.getGroups();
        if (CollUtil.isNotEmpty(groups)) {
            groups.forEach(group -> {
                GenDynamicFormGroupEntity groupEntity = GenDynamicFormGroupConvert.INSTANCE.convertFormEntity(group);
                groupEntity.setId(null);
                groupEntity.setFormId(formEntity.getId());
                dynamicFormGroupService.save(groupEntity);
                List<GenDynamicFormFieldEntity> elements = group.getElements();
                if (CollUtil.isNotEmpty(elements)) {
                    elements.forEach(element -> {
                        element.setGroupId(groupEntity.getId());
                        element.setFormId(formEntity.getId());
                        element.setId(null);
                    });
                    dynamicFormFieldService.saveBatch(elements);
                }
            });
        }
    }

    /**
     * @param sFunction 函数式获取Key
     * @param keys      Key列表
     * @return 列表
     */
    public List<GenDynamicFormEntity> getListByKeys(SFunction<GenDynamicFormEntity, ?> sFunction, List<Serializable> keys) {
        return list(Wrappers.lambdaQuery(GenDynamicFormEntity.class).in(sFunction, keys));
    }

    /**
     * @param list 解析的数据
     * @return 过滤以后的数据
     */
    public List<GenDynamicFormEntity> filterDynamicImport(List<GenDynamicFormEntity> list) {
        return list;
    }

    /**
     * @param list 解析的数据
     * @return 返回过滤的数据
     * @description 覆盖导入的数据
     */
    public List<GenDynamicFormEntity> overrideDynamicImport(List<GenDynamicFormEntity> list) {
        return Collections.emptyList();
    }

    private FormConfigVO getFormConfigById(Integer id) {
        GenDynamicFormEntity dynamicForm = getById(id);

        if (Objects.isNull(dynamicForm)) {
            return getDynamicForm(new FormConfigVO());
        }

        FormConfigVO formConfigVO = GenDynamicFormConvert.INSTANCE.convert(dynamicForm);
        formConfigVO.setGroups(dynamicFormGroupService.getFormGroupsByFormId(id));
        return formConfigVO;
    }

    private String generateActivityCode() {
        return RandomUtil.randomString(10);
    }

    private List<GenDynamicFormEntity> getListDataByArray(GenDynamicFormQuery query) {
        return getListDataByKey(query.getCode(), query.getCodes());
    }

    private List<GenDynamicFormEntity> getListDataByKey(String key, Collection<Serializable> codes) {
        if (CollUtil.isEmpty(codes)) {
            return Collections.emptyList();
        }
        return list(Wrappers.query(getEntityClass()).in(key, codes));
    }

}